home *** CD-ROM | disk | FTP | other *** search
- #include <stdlib.h>
- #include <string.h>
- #include <conio.h>
- #include <dos.h>
-
- #include "boolean.h"
- #include "vga.h"
-
- char * const screen_lin_addr = (char *) 0xA0000;
-
- const video_int = 0x10;
-
- const screen_width = 320;
- const screen_height = 200;
- const bytes_per_row = 320;
-
- //----------------------------------------------------------------------------
- // The VGA object. (Only one is allowed.)
- //----------------------------------------------------------------------------
-
- vga_t vga;
-
- //----------------------------------------------------------------------------
- // The offscreen drawing buffer.
- //----------------------------------------------------------------------------
-
- static char vga_buf [ 64000 ];
-
- //----------------------------------------------------------------------------
- // FUNCTION swap
- //----------------------------------------------------------------------------
-
- inline void swap
- (
- int& var1,
- int& var2
- )
- {
- int temp;
-
- temp = var1;
- var1 = var2;
- var2 = temp;
- }
-
- //----------------------------------------------------------------------------
- // FUNCTION vga_t::exists
- //----------------------------------------------------------------------------
- // Checks to see if there is a VGA display adapter. Returns true if there
- // is, false if there isn't.
- //----------------------------------------------------------------------------
-
- boolean vga_t::exists
- (
- void
- )
- {
- boolean exists;
- union REGS regs;
-
- regs.h.ah = 0x1A;
- regs.h.al = 0;
-
- int386 ( video_int, & regs, & regs );
-
- if ( regs.h.al == 0x1A )
- exists = true;
- else
- exists = false;
-
- return exists;
- }
-
- //----------------------------------------------------------------------------
- // FUNCTION vga_t::start
- //----------------------------------------------------------------------------
- // Saves the current video mode and switches to mode 13h.
- //----------------------------------------------------------------------------
-
- void vga_t::start
- (
- void
- )
- {
- union REGS regs;
-
- regs.x.eax = 0x0013;
-
- int386 ( video_int, & regs, & regs );
- }
-
- //----------------------------------------------------------------------------
- // FUNCTION vga_t::end
- //----------------------------------------------------------------------------
- // Restores the previous video mode.
- //----------------------------------------------------------------------------
-
- void vga_t::end
- (
- void
- )
- {
- union REGS regs;
-
- regs.x.eax = 0x0003;
-
- int386 ( video_int, & regs, & regs );
- }
-
- //----------------------------------------------------------------------------
- // FUNCTION vga_t::update
- //----------------------------------------------------------------------------
- // Copies the drawing buffer into screen memory.
- //----------------------------------------------------------------------------
-
- void vga_t::update
- (
- void
- )
- {
- // while ( (inp (0x3da) & 8) != 0 )
- // ;
-
- // while ( (inp (0x3da) & 8) == 0 )
- // ;
-
- memcpy ( screen_lin_addr, vga_buf, 64000 );
- }
-
- //----------------------------------------------------------------------------
- // FUNCTION vga_t::clear
- //----------------------------------------------------------------------------
- // Fills the entire screen buffer with the given color.
- //----------------------------------------------------------------------------
-
- void vga_t::clear
- (
- int color
- )
- {
- memset ( vga_buf, color, sizeof (vga_buf) );
- }
-
- //----------------------------------------------------------------------------
- // FUNCTION win_t::resize
- //----------------------------------------------------------------------------
- // Resizes the clipping window to the given coordinates.
- //----------------------------------------------------------------------------
-
- void win_t::resize
- (
- int new_x1,
- int new_y1,
- int new_x2,
- int new_y2
- )
- {
- x1 = new_x1;
- y1 = new_y1;
- x2 = new_x2;
- y2 = new_y2;
- }
-
- //----------------------------------------------------------------------------
- // FUNCTION win_t::clear
- //----------------------------------------------------------------------------
- // Fills a window with the given color.
- //----------------------------------------------------------------------------
-
- void win_t::clear
- (
- int color
- )
- {
- char * addr;
- int width;
- int height;
-
- addr = vga_buf + (y1 * bytes_per_row) + x1;
- width = x2 - x1;
- height = y2 - y1;
-
- while ( height > 0 )
- {
- memset ( addr, color, width );
-
- addr += bytes_per_row;
- height -= 1;
- }
- }
-
- //----------------------------------------------------------------------------
- // FUNCTION win_t::point
- //----------------------------------------------------------------------------
- // Draws a point that is clipped to the given window.
- //----------------------------------------------------------------------------
-
- void win_t::point
- (
- int x,
- int y,
- int color
- )
- {
- if ( x >= x1 && x < x2 && y >= y1 && y < y2 )
- {
- vga_buf [ y*bytes_per_row + x ] = (char) color;
- }
- }
-
- //----------------------------------------------------------------------------
- // FUNCTION win_t::rect
- //----------------------------------------------------------------------------
- // Draws a filled rectangle that is clipped to the given window.
- //----------------------------------------------------------------------------
-
- void win_t::rect
- (
- int rect_x1,
- int rect_y1,
- int rect_x2,
- int rect_y2,
- int color
- )
- {
- char * addr;
- int width;
- int height;
-
- if ( rect_x2 < x1 || rect_x1 >= x2 ||
- rect_y2 < y1 || rect_y1 >= y2 )
- goto exit_func;
-
- if ( rect_x1 < x1 )
- rect_x1 = x1;
-
- if ( rect_x2 > x2 )
- rect_x2 = x2;
-
- if ( rect_y1 < y1 )
- rect_y1 = y1;
-
- if ( rect_y2 > y2 )
- rect_y2 = y2;
-
- addr = vga_buf + (rect_y1 * bytes_per_row) + rect_x1;
- width = rect_x2 - rect_x1;
- height = rect_y2 - rect_y1;
-
- if ( width > 0 )
- {
- while ( height > 0 )
- {
- memset ( addr, color, width );
-
- addr += bytes_per_row;
- height -= 1;
- }
- }
-
- exit_func:
-
- return;
- }
-
- //----------------------------------------------------------------------------
- // FUNCTION win_t::line
- //----------------------------------------------------------------------------
- // Draws a line that is clipped to the given window.
- //----------------------------------------------------------------------------
-
- void win_t::line
- (
- int line_x1,
- int line_y1,
- int line_x2,
- int line_y2,
- int color
- )
- {
- int delta_x;
- int delta_y;
-
- // Switch the points so that (line_x1,line_y1) is always the top one.
-
- if ( line_y2 < line_y1 )
- {
- swap ( line_x1, line_x2 );
- swap ( line_y1, line_y2 );
- }
-
- // Compute the x and y deltas.
-
- delta_x = line_x2 - line_x1;
- delta_y = line_y2 - line_y1;
-
- // Clip the line on the left and right edges.
-
- if ( line_x1 < x1 )
- {
- if ( line_x2 < x1 ) goto exit_func;
-
- line_y1 += ( delta_y * ( x1 - line_x1 ) / delta_x );
- line_x1 = x1;
- }
- else if ( line_x1 >= x2 )
- {
- if ( line_x2 >= x2 ) goto exit_func;
-
- line_y1 += ( delta_y * ( x2 - line_x1 ) / delta_x );
- line_x1 = x2 - 1;
- }
-
- if ( line_x2 < x1 )
- {
- line_y2 += ( delta_y * ( x1 - line_x2 ) / delta_x );
- line_x2 = x1;
- }
- else if ( line_x2 >= x2 )
- {
- line_y2 += ( delta_y * ( x2 - line_x2 ) / delta_x );
- line_x2 = x2 - 1;
- }
-
- // Don't draw lines that are completely off the screen.
-
- if ( line_y2 < y1 || line_y1 >= y2 ) goto exit_func;
-
- // Clip the line on the top edge.
-
- if ( line_y1 < y1 )
- {
- line_x1 += ( delta_x * ( y1 - line_y1 ) / delta_y );
- line_y1 = y1;
-
- if ( line_x1 < x1 ) line_x1 = x1;
- if ( line_x1 >= x2 ) line_x1 = x2 - 1;
- }
-
- // Clip the line on the bottom edge.
-
- if ( line_y2 >= y2 )
- {
- line_x2 += ( delta_x * ( y2 - line_y2 ) / delta_y );
- line_y2 = y2 - 1;
-
- if ( line_x2 < x1 ) line_x2 = x1;
- if ( line_x2 >= x2 ) line_x2 = x2 - 1;
- }
-
- // Recompute the x and y deltas using the clipped coordinates.
-
- delta_x = line_x2 - line_x1;
- delta_y = line_y2 - line_y1;
-
- // Draw the line.
-
- {
- char * pixel_addr;
- int denominator;
- int nr_pixels;
- int frac_x;
- int frac_y;
- int add_x;
- const int add_y = bytes_per_row;
-
-
- if (delta_x > 0)
- {
- add_x = 1;
- }
- else
- {
- add_x = -1;
- delta_x = -delta_x;
- }
-
- if ( delta_y > delta_x )
- {
- denominator = delta_y;
- nr_pixels = delta_y + 1;
- }
- else
- {
- denominator = delta_x;
- nr_pixels = delta_x + 1;
- }
-
- frac_y = frac_x = denominator >> 1;
-
- pixel_addr = vga_buf + bytes_per_row*line_y1 + line_x1;
-
- for ( ; nr_pixels > 0; -- nr_pixels )
- {
- *pixel_addr = (char) color;
-
- frac_x += delta_x;
-
- if ( frac_x > denominator )
- {
- frac_x -= denominator;
- pixel_addr += add_x;
- }
-
- frac_y += delta_y;
-
- if ( frac_y > denominator )
- {
- frac_y -= denominator;
- pixel_addr += add_y;
- }
- }
- }
-
- exit_func:
-
- return;
- }
-
- //----------------------------------------------------------------------------
- // FUNCTION win_t::convex_poly
- //----------------------------------------------------------------------------
- // Draws a filled polygon that is clipped to the given window.
- //
- // Limitations: Polygon MUST be convex;
- // Vertex coordinates MUST be given in clockwise order around the
- // polygon.
- //----------------------------------------------------------------------------
-
- void win_t::convex_poly
- (
- int nr_points,
- scr_xy_p_t points,
- int color
- )
- {
- int left_x [ screen_height ];
- int right_x [ screen_height ];
-
- int min_y;
- int max_y;
-
- int p1;
- int p2;
-
- // Load the edges into the left_x and right_x arrays, and find the minimum
- // and maximum Y coordinates of the polygon.
-
- min_y = screen_height;
- max_y = 0;
-
- for ( p1 = 0; p1 < nr_points; ++ p1 )
- {
- int * edge_x;
- int px1;
- int py1;
- int px2;
- int py2;
- int delta_x;
- int delta_y;
-
-
- p2 = (p1 + 1) % nr_points;
-
- px1 = points [p1].x;
- py1 = points [p1].y;
- px2 = points [p2].x;
- py2 = points [p2].y;
-
- delta_y = py2 - py1;
-
- // Throw out horizontal lines, and choose which side to put the rest on.
-
- if ( delta_y == 0 )
- {
- continue;
- }
- else if ( delta_y > 0 )
- {
- edge_x = right_x;
- }
- else
- {
- edge_x = left_x;
-
- // Swap points so (px1, py1) is the top point.
-
- delta_y = -delta_y;
-
- swap ( px1, px2 );
- swap ( py1, py2 );
- }
-
- delta_x = px2 - px1;
-
- // Ignore edges that are completely off the top or bottom of the screen.
-
- if ( py2 < y1 || py1 >= y2 ) continue;
-
- // Clip the edge with the top of the window.
-
- if ( py1 < y1 )
- {
- px1 += ( delta_x * ( y1 - py1 ) / delta_y );
- py1 = y1;
- }
-
- // Clip the edge with the bottom of the window.
-
- if ( py2 > y2 )
- {
- px2 += ( delta_x * ( y2 - py2 ) / delta_y );
- py2 = y2;
- }
-
- // Adjust the minimum and maximum Y coordinates if necessary.
-
- if ( py1 < min_y )
- min_y = py1;
-
- if ( py2 > max_y )
- max_y = py2;
-
- // Recompute the X and Y deltas using the clipped coordinates.
-
- delta_x = px2 - px1;
- delta_y = py2 - py1;
-
- // Load the edge into the chosen edge array.
-
- int x;
- int y;
- int x_inc;
- int x_error;
-
-
- if (delta_x > 0)
- {
- x_inc = 1;
- }
- else
- {
- x_inc = -1;
- delta_x = -delta_x;
- }
-
- x = px1;
- x_error = 0;
-
- // Move the right edge one pixel to the right.
-
- if ( edge_x == right_x )
- {
- ++ x;
- }
-
- for ( y = py1; y < py2; ++ y )
- {
- // Load the edge array with the clipped X coordinate.
-
- if ( x < x1 )
- {
- edge_x [y] = x1;
- }
- else if ( x > x2 )
- {
- edge_x [y] = x2;
- }
- else
- {
- edge_x [y] = x;
- }
-
- x_error += delta_x;
-
- while ( x_error >= delta_y )
- {
- x += x_inc;
- x_error -= delta_y;
- }
- }
- }
-
- // Now draw the scan line segments.
-
- char * row_addr;
- char * addr;
- int width;
- int y;
-
- if ( max_y <= min_y ) goto exit_func;
-
- row_addr = vga_buf + (min_y * bytes_per_row);
-
- for ( y = min_y; y < max_y; ++ y )
- {
- addr = row_addr + left_x [y];
- width = right_x [y] - left_x [y];
-
- memset ( addr, color, width );
-
- row_addr += bytes_per_row;
- }
-
- exit_func:
-
- return;
- }
-
- //----------------------------------------------------------------------------
- // FUNCTION win_t::v_trapezoid
- //----------------------------------------------------------------------------
- // Draws a vertical trapezoid that is clipped to the given window.
- //----------------------------------------------------------------------------
-
- typedef struct
- {
- int y; // Y coordinate of edge
- int y_inc; // Direction of Y advance
- int y_numerator; // Numerator of the slope fraction
- int y_denominator; // Denominator of the slope fraction
- int y_error; // Fractional error accumulator
- }
- edge_t;
-
- typedef edge_t * edge_p_t;
-
- //----------------------------------------------------------------------------
-
- inline void init
- (
- edge_t & edge,
- int x1,
- int y1,
- int x2,
- int y2
- )
- {
- edge.y = y1;
- edge.y_inc = (y2 > y1) ? 1 : -1;
- edge.y_numerator = (y2 > y1) ? (y2 - y1) : (y1 - y2);
- edge.y_denominator = x2 - x1;
- edge.y_error = (edge.y_denominator + 1) / 2;
- }
-
- //----------------------------------------------------------------------------
-
- inline void update
- (
- edge_t & edge
- )
- {
- edge.y_error -= edge.y_numerator;
-
- while ( edge.y_error < 0 )
- {
- edge.y += edge.y_inc;
- edge.y_error += edge.y_denominator;
- }
- }
-
- //----------------------------------------------------------------------------
-
- inline void draw_col
- (
- int x,
- int y1,
- int y2,
- int win_y1,
- int win_y2,
- int color
- )
- {
- char * addr;
- int height;
-
-
- if ( y2 < win_y1 || y1 >= win_y2 ) goto exit_func;
-
- if ( y1 < win_y1 )
- y1 = win_y1;
-
- if ( y2 > win_y2 )
- y2 = win_y2;
-
-
- addr = vga_buf + bytes_per_row * y1 + x;
-
- for ( height = y2 - y1; height > 0; -- height )
- {
- *addr = (char) color;
-
- addr += bytes_per_row;
- }
-
- exit_func:
-
- return;
- }
-
- //----------------------------------------------------------------------------
-
- void win_t::v_trapezoid
- (
- int l_x, // Left X
- int lt_y, // Left Top Y
- int lb_y, // Left Bottom Y
- int r_x, // Right X
- int rt_y, // Right Top Y
- int rb_y, // Right Bottom Y
- int color
- )
- {
- int delta_x;
- int delta_y_t;
- int delta_y_b;
- int x;
- edge_t top, bot;
-
-
- // The trapezoid will be drawn with vertical lines.
-
- // Compute deltas. Make l_x < r_x.
-
- delta_x = r_x - l_x;
-
- if ( delta_x < 0 )
- {
- swap ( l_x, r_x );
- swap ( lt_y, rt_y );
- swap ( lb_y, rb_y );
-
- delta_x = -delta_x;
- }
-
- delta_y_t = rt_y - lb_y;
- delta_y_b = rb_y - lb_y;
-
- // Initialize the top and bottom edge structures.
-
- init ( top, l_x, lt_y, r_x, rt_y );
- init ( bot, l_x, lb_y, r_x, rb_y );
-
- // Throw out trapezoids that are completely off the left or right side of
- // the view window.
-
- if ( r_x < x1 || l_x >= x2 ) goto exit_func;
-
- // Clip against left edge.
-
- if ( l_x < x1 )
- {
- lt_y += ( delta_y_t * ( x1 - l_x ) / delta_x );
- lb_y += ( delta_y_b * ( x1 - l_x ) / delta_x );
- l_x = x1;
- }
-
- // Clip against right edge.
-
- if ( r_x >= x2 )
- {
- rt_y += ( delta_y_t * ( x2 - r_x ) / delta_x );
- rb_y += ( delta_y_b * ( x2 - r_x ) / delta_x );
- r_x = x2;
- }
-
- // Draw the columns.
-
- for ( x = l_x; x < r_x; ++ x )
- {
- draw_col ( x, top.y, bot.y, y1, y2, color );
-
- update ( top );
- update ( bot );
- }
-
- exit_func:
-
- return;
- }
-
-